import struct
from log_manager import LogManager
class ProtocolParser:
    """协议解析器"""
    # 协议头
    HEADER = 0xAAAAAAAA
    
    # 协议状态定义
    STATE_IDLE = 0
    STATE_HEAD1 = 1
    STATE_HEAD2 = 2
    STATE_HEAD3 = 3
    STATE_HEAD4 = 4
    STATE_LEN1 = 5
    STATE_LEN2 = 6
    STATE_LEN3 = 7
    STATE_LEN4 = 8
    STATE_CMD = 9
    STATE_DATA = 10
    STATE_CRC1 = 11
    STATE_CRC2 = 12
    
    # 协议命令定义
    CMD_GET_DEVICE_INFO = 0x01
    CMD_GET_UDISK_INFO = 0x02
    CMD_GET_FILE_LIST = 0x03
    CMD_MKDIR = 0x04
    CMD_READ_FILE = 0x05
    CMD_WRITE_FILE_START = 0x06
    CMD_WRITE_FILE_DATA = 0x07
    CMD_WRITE_FILE_END = 0x08
    
    # 文件类型定义
    FILE_TYPE_FILE = 0      # 文件
    FILE_TYPE_DIRECTORY = 1 # 文件夹
    
    def __init__(self):
        self.reset()
    
    def reset(self):
        """重置解析器状态"""
        self.state = self.STATE_IDLE
        self.cmd = 0
        self.length = 0
        self.data = bytearray()
        self.crc = 0
    
    def parse_byte(self, byte):
        """解析单个字节"""
        if self.state == self.STATE_IDLE:
            if byte == (self.HEADER >> 24) & 0xFF:
                self.state = self.STATE_HEAD1
                self.data = bytearray([byte])  # 开始收集数据用于CRC计算
        elif self.state == self.STATE_HEAD1:
            if byte == (self.HEADER >> 16) & 0xFF:
                self.state = self.STATE_HEAD2
                self.data.append(byte)
            else:
                self.state = self.STATE_IDLE
        elif self.state == self.STATE_HEAD2:
            if byte == (self.HEADER >> 8) & 0xFF:
                self.state = self.STATE_HEAD3
                self.data.append(byte)
            else:
                self.state = self.STATE_IDLE
        elif self.state == self.STATE_HEAD3:
            if byte == self.HEADER & 0xFF:
                self.state = self.STATE_LEN1
                self.data.append(byte)
            else:
                self.state = self.STATE_IDLE
        elif self.state == self.STATE_LEN1:
            self.length = byte
            self.data.append(byte)
            self.state = self.STATE_LEN2
        elif self.state == self.STATE_LEN2:
            self.length |= byte << 8
            self.data.append(byte)
            self.state = self.STATE_LEN3
        elif self.state == self.STATE_LEN3:
            self.length |= byte << 16
            self.data.append(byte)
            self.state = self.STATE_LEN4
        elif self.state == self.STATE_LEN4:
            self.length |= byte << 24
            self.data.append(byte)
            self.state = self.STATE_CMD
        elif self.state == self.STATE_CMD:
            self.cmd = byte
            self.data.append(byte)
            if self.length > 0:
                self.state = self.STATE_DATA
                self.payload = bytearray()
            else:
                self.state = self.STATE_CRC1
        elif self.state == self.STATE_DATA:
            self.data.append(byte)
            self.payload.append(byte)
            if len(self.payload) >= self.length:
                self.state = self.STATE_CRC1
        elif self.state == self.STATE_CRC1:
            self.crc = byte
            self.state = self.STATE_CRC2
        elif self.state == self.STATE_CRC2:
            self.crc |= byte << 8
            
            # 计算CRC
            calc_crc = self.calc_crc16(self.data)
            
            # 验证CRC
            if calc_crc == self.crc:
                result = (self.cmd, bytes(self.payload) if hasattr(self, 'payload') else b'')
                self.reset()
                return result
            else:
                LogManager.warning(f"CRC校验失败: calc={calc_crc:04X}, recv={self.crc:04X}")
                self.reset()
                
        return None

    def pack(self, cmd, data=None):
        """打包数据
        
        Args:
            cmd: 命令字
            data: 数据负载，可以是bytes或None
            
        Returns:
            bytes: 打包后的数据
        """
        # 如果data为None，使用空bytes
        if data is None:
            data = b''
            
        # 计算长度
        length = len(data)
        
        # 构建数据包头部
        header = bytearray()
        header.extend(self.HEADER.to_bytes(4, 'big'))
        header.extend(length.to_bytes(4, 'little'))
        header.append(cmd)
        
        # 构建完整数据包
        packet = header + data
        
        # 计算CRC
        crc = self.calc_crc16(packet)
        
        # 添加CRC
        packet = bytearray(packet)
        packet.extend(crc.to_bytes(2, 'little'))
        
        return bytes(packet)

    @staticmethod
    def calc_crc16(data):
        """计算CRC16
        
        Args:
            data: 要计算的数据
            
        Returns:
            int: CRC16值
        """
        crc = 0xFFFF
        for byte in data:
            crc ^= byte
            for _ in range(8):
                if crc & 0x0001:
                    crc = (crc >> 1) ^ 0xA001
                else:
                    crc = crc >> 1
        return crc
    
    @staticmethod
    def parse_device_info(payload):
        """解析设备信息响应
        
        设备信息格式:
        struct device_info {
            uint32_t hw_version;    // 硬件版本号 (0x01000000 = 1.0.0)
            uint32_t sw_version;    // 软件版本号 (0x01010000 = 1.1.0)
            uint32_t proto_version; // 协议版本号 (0x01000000 = 1.0.0)
        };
        """
        try:
            if len(payload) >= 12:  # 至少需要3个uint32_t
                info = {}
                
                # 解析版本号
                hw_ver, sw_ver, proto_ver = struct.unpack('>III', payload[:12])  # 改为大端序
                
                # 格式化版本号
                def format_version(ver):
                    return f"{ver&0xFF}.{(ver>>16)&0xFF}.{ver>>24}"
                    
                info['hw_version'] = format_version(hw_ver)      # 1.0.0
                info['sw_version'] = format_version(sw_ver)      # 1.1.0
                info['proto_version'] = format_version(proto_ver) # 1.0.0
                
                LogManager.debug(f"解析设备信息: {info}")
                return info
                
        except Exception as e:
            LogManager.error(f"解析设备信息出错: {str(e)}")
        return None

    @staticmethod
    def parse_udisk_info(payload):
        """解析U盘信息响应"""
        try:
            if len(payload) >= 24:  # 至少需要基本信息的长度
                info = {}
                offset = 0
                
                # 按照设备端结构体定义的顺序解析
                # uint64_t capacity
                info['capacity'], = struct.unpack('<Q', payload[offset:offset+8])
                offset += 8
                
                # uint32_t sector_count
                info['sector_count'], = struct.unpack('<I', payload[offset:offset+4])
                offset += 4
                
                # uint32_t sector_size
                info['sector_size'], = struct.unpack('<I', payload[offset:offset+4])
                offset += 4
                
                # uint16_t id_product
                info['idProduct'], = struct.unpack('<H', payload[offset:offset+2])
                offset += 2
                
                # uint16_t id_vendor
                info['idVendor'], = struct.unpack('<H', payload[offset:offset+2])
                offset += 2
                
                # 字符串描述符
                if len(payload) >= offset + 96:  # 3个32字节的字符串
                    info['iManufacturer'] = payload[offset:offset+32].split(b'\0')[0].decode('ascii')
                    offset += 32
                    info['iProduct'] = payload[offset:offset+32].split(b'\0')[0].decode('ascii')
                    offset += 32
                    info['iSerialNumber'] = payload[offset:offset+32].split(b'\0')[0].decode('ascii')
                
                return info
        except Exception as e:
            print(f"解析U盘信息出错: {str(e)}")
        return None
    
    @staticmethod
    def parse_file_list(payload):
        """解析文件列表响应
        
        文件列表格式:
        struct file_info {
            char file_name[64];    // 固定长度64字节的文件名
            int type;              // 0: 文件，1: 文件夹
            uint32_t modify_time;  // 修改时间
            uint32_t size;         // 文件大小
        };
        """
        try:
            files = []
            offset = 0
            struct_size = 64 + 4 + 4 + 4  # 文件名64字节 + type4字节 + time4字节 + size4字节
            
            while offset + struct_size <= len(payload):
                # 解析文件名(固定64字节)
                name_bytes = payload[offset:offset+64]
                # 找到实际文件名结束位置(NULL结尾)
                name_end = name_bytes.find(b'\0')
                if name_end != -1:
                    name_bytes = name_bytes[:name_end]
                
                try:
                    name = name_bytes.decode('gbk')
                except UnicodeDecodeError:
                    try:
                        name = name_bytes.decode('utf-8')
                    except UnicodeDecodeError:
                        name = name_bytes.decode('latin1')
                
                offset += 64
                
                # 解析类型、时间和大小
                type_val, modify_time, size = struct.unpack('<III', payload[offset:offset+12])
                offset += 12
                
                # 跳过空文件名
                if not name.strip():
                    continue
                    
                # 添加文件信息
                files.append({
                    'name': name,
                    'type': type_val,  # 0=文件, 1=文件夹
                    'size': size,
                    'mtime': modify_time,
                    'is_directory': type_val == ProtocolParser.FILE_TYPE_DIRECTORY
                })
                
            LogManager.debug(f"解析到 {len(files)} 个文件")
            return files
            
        except Exception as e:
            LogManager.error(f"解析文件列表出错: {str(e)}")
            return None
    
    # ... 其他方法保持不变 ... 